package org.jvm.rtda.thread;

import org.jvm.rtda.Object;
import org.jvm.rtda.*;

/**
 * 栈帧中的操作数栈
 *
 * @author 海燕
 * @date 2023/1/12
 */
public class OperandStack extends Slots {

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder("OperandStack:[");
        for (int i = 0; i < this.size; i++) {
            stringBuilder.append(this.localVars[i].getNum() + ",");
        }
        return stringBuilder.append("]").toString();
    }

    /**
     * 栈顶位置
     */
    private int size;

    /**
     * @param maxStack 最大操作数栈深度
     */
    public OperandStack(int maxStack) {
        super(maxStack);
        this.size = 0;
    }


    public void pushInt(int val) {
        setInt(this.size++, val);
    }

    public void pushBoolean(boolean val) {
        pushInt(val ? 1 : 0);
    }

    public boolean popBoolean() {
        return popInt() == 1;
    }


    public int popInt() {
        return getInt(--this.size);
    }

    public void pushFloat(float val) {
        setFloat(this.size++, val);
    }

    public float popFloat() {
        return getFloat(--this.size);
    }


    public void pushLong(long val) {
        setLong(this.size, val);
        this.size += 2;
    }

    public long popLong() {
        this.size -= 2;
        long res = getLong(this.size);
        return res;
    }

    public void pushDouble(double val) {
        setDouble(this.size, val);
        this.size += 2;
    }

    public double popDouble() {
        this.size -= 2;
        double res = getDouble(this.size);
        return res;
    }

    public void pushRef(Object val) {
        setRef(this.size++, val);
    }

    /**
     * 根据参数类型进行入栈
     *
     * @param val
     */
    public void pushByType(java.lang.Object val) {
        if (val instanceof Object) {
            pushRef((Object) val);
        } else if (val instanceof Integer) {
            pushInt((int) val);
        } else if (val instanceof Long) {
            pushLong((long) val);
        } else if (val instanceof Boolean) {
            pushBoolean((boolean) val);
        } else if (val instanceof Byte) {
            pushInt(((byte) val) & 0x0FF);
        } else if (val instanceof Character) {
            pushInt(((char) val) & 0x0FFFF);
        } else if (val instanceof Short) {
            pushInt(((short) val) & 0x0FFFF);
        } else if (val instanceof Float) {
            pushFloat((float) val);
        } else if (val instanceof Double) {
            pushDouble((double) val);
        }
    }

    public java.lang.Object popByType(String type) {
        switch (type) {
            case "V":
                return null;
            case "Z":
                return popBoolean();
            case "B":
                return (byte) popInt();
            case "C":
                return (char) popInt();
            case "S":
                return (short) popInt();
            case "I":
                return popInt();
            case "J":
                return popLong();
            case "F":
                return popFloat();
            case "D":
                return popDouble();
            default:
                return popRef();
        }
    }


    public Object popRef() {
        return getRef(--this.size);
    }

    public void pushSlot(Slot val) {
        setSlot(this.size++, val);
    }

    public Slot popSlot() {
        return getSlot(--this.size);
    }

    public Slot topSlot() {
        return getSlot(this.size - 1);
    }

    /**
     * 在实例方法调用时，先行在操作数栈中获取实例的引用
     *
     * @param
     * @return
     */
    public Object getRefFromTop(int n) {
        return getRef(this.size - 1 - n);
    }

    /**
     * 清空操作数栈
     */
    public void clear() {
        this.size = 0;
    }

    public boolean isEmpty() {
        return size <= 0;
    }
}
